import { newArrayProto } from "./array";
import Dep from "./dep";

class Observer {
  constructor(data) {
    this.dep = new Dep();

    Object.defineProperty(data, "__ob__", {
      value: this,
      enumerable: false,
    });
    // data.__ob__ = this //给数据加了一个标识，如果数据上有__ob__ 则说明这个属性被观测过了
    if (Array.isArray(data)) {
      data.__proto__ = newArrayProto;
      this.observeArray(data);
    } else {
      this.walk(data);
    }
  }
  walk(data) {
    //循环对象，对属性依次劫持
    // '重新定义'属性 性能差
    Object.keys(data).forEach((key) => defineReactive(data, key, data[key]));
  }
  observeArray(data) {
    data.forEach((item) => observe(item));
  }
}
// 深层次嵌套会递归，递归多了性能差，不存在的属性监控不到，存在的属性要重写方法  解决：vue3 --> proxy
function dependArray(value) {
  for (let i = 0; i < value.length; i++) {
    let current = value[i];
    current.__ob__ && current.__ob__.dep.depend();
    if (Array.isArray(current)) {
      dependArray(current);
    }
  }
}
// 将劫持的对象赋予响应式
export function defineReactive(target, key, value) {
  let childOb = observe(value);
  let dep = new Dep(); //每一个属性都有dep
  Object.defineProperty(target, key, {
    get() {
      //取值的时候执行get
      if (Dep.target) {
        dep.depend(); //让这个属性的收集器记住当前的watcher
        if (childOb) {
          childOb.dep.depend(); //让数组和对象本身也实现依赖收集
          if (Array.isArray(value)) {
            dependArray(value);
          }
        }
      }
      return value;
    },
    set(newValue) {
      //修改的时候执行set
      if (newValue === value) return;
      observe(newValue);
      value = newValue;
      dep.notify(); //通知更新
    },
  });
}
export function observe(data) {
  // 对data进行劫持
  if (typeof data !== "object" || data == null) {
    return; //只对对象进行劫持
  }
  if (data.__ob__ instanceof Observer) {
    return data.__ob__;
  }
  // 如果一个对象被劫持过，据不需要再劫持了(增添一个实例，用实例来判断是否被劫持过)
  return new Observer(data);
}
